package com.beiding.hotcode;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ClasspathContext {


    private Set<FileMonitor> classPathMonitors = new HashSet<>();

    private ClassLoader contextClassLoader = new URLClassLoader(new URL[0], null);

    private boolean change = false;

    boolean checkChange() {
        if (change) {
            return true;
        }


        //检查文件的变化
        for (FileMonitor monitor : classPathMonitors) {
            if (monitor.checkChange()) {
                change = true;
            }
        }

        return change;
    }

    synchronized ClassLoader getContextClassLoader() {
        //重新计算类路径
        if (change) {
            List<URL> urls = new ArrayList<>();
            for (FileMonitor monitor : classPathMonitors) {
                File file = monitor.getFile();
                if (file.exists()) {
                    try {
                        urls.add(file.toURI().toURL());
                    } catch (MalformedURLException e) {
                        System.out.println("url问题");
                    }
                }
            }
            URL[] us = new URL[urls.size()];
            urls.toArray(us);
            contextClassLoader = new URLClassLoader(us, null);
            for (FileMonitor classPathMonitor : classPathMonitors) {
                classPathMonitor.resetChange();
            }
            change = false;
        }

        return contextClassLoader;
    }

    public void addClassPath(File file) {
        addClassPath(new FileMonitor(file));
    }

    public synchronized void removeClassPath(File file) {
        for (FileMonitor monitor : classPathMonitors) {
            if (monitor.getFile().equals(file)) {
                removeClassPath(monitor);
                break;
            }
        }
    }


    //添加文件进行检测
    synchronized void addClassPath(FileMonitor monitor) {
        classPathMonitors.add(monitor);
        //添加前检查一次变化
        monitor.checkChange();
        change = true;
    }

    synchronized void removeClassPath(FileMonitor monitor) {
        boolean remove = classPathMonitors.remove(monitor);
        if (remove) {
            change = true;
        }
    }

    //可以添加包,类或其他
    synchronized void add(JavaMonitor javaMonitor) {
        javaMonitor.setClasspathContext(this);
    }

    synchronized void add(MonitorGroup monitorGroup) {
        monitorGroup.setClasspathContext(this);
    }

    public synchronized void add(MyClass myClass) {
        if (myClass instanceof HotClass) {
            JavaMonitor javaMonitor = ((HotClass) myClass).getJavaMonitor();
            add(javaMonitor);
        }
    }

    public synchronized void add(MyPackage myPackage) {
        if (myPackage instanceof HotPackage) {
            add(((HotPackage) myPackage).monitorGroup);
        }
    }

    public synchronized void remove(MyClass myClass) {
        if (myClass instanceof HotClass) {
            JavaMonitor javaMonitor = ((HotClass) myClass).getJavaMonitor();
            remove(javaMonitor);
        }
    }

    public synchronized void remove(MyPackage myPackage) {
        if (myPackage instanceof HotPackage) {
            remove(((HotPackage) myPackage).monitorGroup);
        }
    }


    synchronized void remove(JavaMonitor javaMonitor) {
        if (javaMonitor.getClasspathContext() == this) {
            javaMonitor.setClasspathContext(null);
        }
    }

    synchronized void remove(MonitorGroup monitorGroup) {
        if (monitorGroup.getClasspathContext() == this) {
            monitorGroup.setClasspathContext(null);
        }
    }

}
